home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / WASTE 1.2 Distribution / WASTE 1.2 / WEScraps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-18  |  11.4 KB  |  444 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEScraps.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Routines for Manipulating Style Scraps and Object Soups
  6.  *
  7.  *  Copyright (c) 1993-1996 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. pascal OSErr _WEPrependStyle(Handle hStyleScrap, const WERunInfo *info, SInt32 offsetDelta)
  18. {
  19.     // compare the stylistic attributes in info with the first element of the specified
  20.     // style scrap: if they differ, prepend a new element to the style scrap.
  21.     // in any case, advance all character offsets in the style scrap by offsetDelta
  22.  
  23.     TEStyleScrapPtr pScrap;
  24.     TEStyleScrapElement element;
  25.     SInt16 i;
  26.     OSErr err;
  27.  
  28.     pScrap = * (TEStyleScrapHandle) hStyleScrap;
  29.  
  30.     // compare this style info with that stored in the first element of our private style scrap
  31.     if (!_WEBlockCmp(&pScrap->scrpStyleTab[0].scrpTEAttrs, &info->runAttrs, sizeof(TERunAttributes)))
  32.     {
  33.         // insert a new style scrap element at the beginning of the style scrap
  34.         element.scrpStartChar = 0;
  35.         element.scrpTEAttrs = * (TERunAttributes *) &info->runAttrs;
  36.  
  37.         if ((err = _WEInsertBlock(hStyleScrap, &element, sizeof(element), sizeof(SInt16))) != noErr)
  38.             return err;
  39.  
  40.         pScrap = * (TEStyleScrapHandle) hStyleScrap;
  41.  
  42.         // increment element count
  43.         pScrap->scrpNStyles++;
  44.  
  45.     } // if not _WEBlockCmp
  46.  
  47.     // update char offsets within the style scrap
  48.     for ( i = pScrap->scrpNStyles - 1; i > 0; i-- )
  49.         pScrap->scrpStyleTab[i].scrpStartChar += offsetDelta;
  50.  
  51.     return noErr;
  52.  
  53. }
  54.  
  55. pascal OSErr _WEAppendStyle(Handle hStyleScrap, const WERunInfo *info, SInt32 offset)
  56. {
  57.  
  58.     // compare the stylistic attributes in info with the last element of the specified
  59.     // style scrap: if they differ, append a new element to the style scrap.
  60.  
  61.     TEStyleScrapPtr pScrap;
  62.     TEStyleScrapElement element;
  63.     OSErr err;
  64.  
  65.     pScrap = * (TEStyleScrapHandle) hStyleScrap;
  66.     // compare this style info with that stored in the first element of our private style scrap
  67.     if (!_WEBlockCmp(&pScrap->scrpStyleTab[pScrap->scrpNStyles - 1].scrpTEAttrs,
  68.         &info->runAttrs, sizeof(TERunAttributes)))
  69.     {
  70.  
  71.         // create a new style scrap element
  72.         element.scrpStartChar = offset;
  73.         element.scrpTEAttrs = * (TERunAttributes *) &info->runAttrs;
  74.  
  75.         // append it at the end of the style scrap
  76.         err = PtrAndHand(&element, hStyleScrap, sizeof(element));
  77.         if ((err = MemError()) != noErr)
  78.             return err;
  79.  
  80.         // increment scrap counter
  81.         pScrap = * (TEStyleScrapHandle) hStyleScrap;
  82.         pScrap->scrpNStyles++;
  83.  
  84.     } // if not _WEBlockCmp
  85.  
  86.     // return result code
  87.     return noErr;
  88. }
  89.  
  90. #if WASTE_OBJECTS
  91.  
  92. pascal OSErr _WEPrependObject(Handle hSoup, const WERunInfo *info, SInt32 offsetDelta)
  93. {
  94.     // if info describes an embedded object, prepend a new object descriptor,
  95.     // complete with the associated object data, to the specified soup.
  96.     // in any case, advance all character offsets in the soup by offsetDelta
  97.  
  98.     WEObjectDescHandle hObjectDesc = info->runAttrs.runStyle.tsObject;
  99.     Handle hObjectData = nil;
  100.     FlavorType objectType;
  101.     Boolean disposeData;
  102.     UInt32 pSoup;
  103.     WESoup soup;
  104.     Size soupSize, objectDataSize, extraSize;
  105.     OSErr err;
  106.  
  107.     // get size of existing soup
  108.     soupSize = GetHandleSize(hSoup);
  109.  
  110.     if (hObjectDesc != nil)
  111.     {
  112.         // create a temporary handle for the streaming callback
  113.         if ((err = _WEAllocate(0, kAllocTemp, &hObjectData)) != noErr)
  114.             goto cleanup;
  115.  
  116.         // get the object type/data
  117.         if ((err = _WEStreamObject(weToSoup, &objectType, &hObjectData, &disposeData, hObjectDesc)) != noErr)
  118.             goto cleanup;
  119.  
  120.         // get size of object data
  121.         objectDataSize = GetHandleSize(hObjectData);
  122.  
  123.         // extraSize is size of descriptor + size of object data
  124.         extraSize = sizeof(soup) + objectDataSize;
  125.  
  126.         // fill in a soup item
  127.         BLOCK_CLR(soup);
  128.         soup.soupType = objectType;
  129.         soup.soupSize = (*hObjectDesc)->objectSize;
  130.         soup.soupDataSize = objectDataSize;
  131.  
  132.         // resize the soup
  133.         SetHandleSize(hSoup, extraSize + soupSize);
  134.         if ((err = MemError()) != noErr)
  135.             goto cleanup;
  136.  
  137.         // move old contents forward
  138.         pSoup = (UInt32) *hSoup;
  139.         BlockMoveData((const void *) pSoup, (void *) (pSoup + extraSize), soupSize);
  140.  
  141.         // insert the new object descriptor at the beginning
  142.         BlockMoveData(&soup, (void *) pSoup, sizeof(soup));
  143.  
  144.         // copy the object data
  145.         BlockMoveData(*hObjectData, (void *) (pSoup + sizeof(soup)), objectDataSize);
  146.     }
  147.     else
  148.     {
  149.         pSoup = (UInt32) *hSoup;
  150.         extraSize = 0;
  151.     }
  152.  
  153.     // update char offsets within the soup
  154.     while (soupSize > 0)
  155.     {
  156.         pSoup += extraSize;
  157.  
  158.         //    we have to use BlockMoveData to access descriptors within
  159.         //    the soup, as they might be odd-aligned (duh!) and that would
  160.         //    cause fatal address errors on 68000 CPUs
  161.  
  162.         BlockMoveData((const void *) pSoup, &soup, sizeof(soup));
  163.         soup.soupOffset += offsetDelta;
  164.         BlockMoveData(&soup, (void *) pSoup, sizeof(soup));
  165.         extraSize = sizeof(soup) + soup.soupDataSize;
  166.         soupSize -= extraSize;
  167.     }
  168.  
  169.     err = noErr;
  170.  
  171. cleanup:
  172.     if (disposeData)
  173.         _WEForgetHandle(&hObjectData);
  174.  
  175.     return err;
  176.  
  177. }
  178.  
  179. pascal OSErr _WEAppendObject(Handle hSoup, const WERunInfo *info, SInt32 offset)
  180. {
  181.  
  182.     // if info describes an embedded object, append a new object descriptor,
  183.     // complete with the associated object data, to the specified soup.
  184.  
  185.     WEObjectDescHandle hObjectDesc = info->runAttrs.runStyle.tsObject;
  186.     Handle hObjectData = nil;
  187.     FlavorType objectType;
  188.     WESoup soup;
  189.     Boolean saveDataLock;
  190.     Boolean disposeData;
  191.     OSErr err;
  192.  
  193.     if (hObjectDesc != nil)
  194.     {
  195.         // create a temporary handle for the streaming callback
  196.         if ((err = _WEAllocate(0, kAllocTemp, &hObjectData)) != noErr)
  197.             goto cleanup;
  198.  
  199.         // get the object type/data
  200.         if ((err = _WEStreamObject(weToSoup, &objectType, &hObjectData, &disposeData, hObjectDesc)) != noErr)
  201.             goto cleanup;
  202.  
  203.         // fill in a soup item
  204.         BLOCK_CLR(soup);
  205.         soup.soupOffset = offset;
  206.         soup.soupType = objectType;
  207.         soup.soupSize = (*hObjectDesc)->objectSize;
  208.         soup.soupDataSize = GetHandleSize(hObjectData);
  209.  
  210.         // append it to the soup handle
  211.         PtrAndHand(&soup, hSoup, sizeof(soup));
  212.         if ((err = MemError()) != noErr)
  213.             goto cleanup;
  214.  
  215.         // append the actual object data to the soup handle
  216.         saveDataLock = _WESetHandleLock(hObjectData, true);
  217.         PtrAndHand(*hObjectData, hSoup, soup.soupDataSize);
  218.         err = MemError();
  219.         _WESetHandleLock(hObjectData, saveDataLock);
  220.         if (err != noErr)
  221.             goto cleanup;
  222.     } // if object reference is not nil
  223.  
  224.     err = noErr;
  225.  
  226. cleanup:
  227.     if (disposeData)
  228.         _WEForgetHandle(&hObjectData);
  229.  
  230.     return err;
  231.  
  232. }
  233.  
  234. #endif
  235.  
  236. pascal OSErr WECopyRange(SInt32 rangeStart, SInt32 rangeEnd, Handle hText,
  237.                     Handle hStyles, Handle hSoup, WEHandle hWE)
  238. {
  239.  
  240.     // Make a copy of the specified range of text: store the characters in hText
  241.     // and the associated style scrap in hStyles.  The handles are resized as necessary.
  242.     // Specify nil in hText or hStyles if you don't want the corresponding info returned.
  243.  
  244.     WEPtr pWE;
  245.     TEStyleScrapElementPtr pElement;
  246.     SInt32 rangeLength;
  247.     SInt32 firstRun, nRuns, i;
  248.     SInt32 startChar;
  249.     WERunInfo info;
  250.     Boolean saveWELock;
  251.     OSErr err;
  252.  
  253.     // lock the WE record
  254.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  255.     pWE = *hWE;
  256.  
  257.     // range-check parameters and reorder them if necessary
  258.     rangeStart = _WEPinInRange(rangeStart, 0, pWE->textLength);
  259.     rangeEnd = _WEPinInRange(rangeEnd, 0, pWE->textLength);
  260.     _WEReorder(&rangeStart, &rangeEnd);
  261.     rangeLength = rangeEnd - rangeStart;
  262.  
  263.     if (hText != nil)
  264.     {
  265.         // resize the given handle
  266.         SetHandleSize(hText, rangeLength);
  267.         if ((err = MemError()) != noErr)
  268.             goto cleanup;
  269.  
  270.         // copy the text range
  271.         BlockMoveData((Ptr) *pWE->hText + rangeStart, (Ptr) *hText, rangeLength);
  272.     }
  273.  
  274.     // make the soup handle zero-length
  275.     if (hSoup != nil)
  276.     {
  277.         SetHandleSize(hSoup, 0);
  278.         if ((err = MemError()) != noErr)
  279.             goto cleanup;
  280.     }
  281.  
  282.     if ((hStyles != nil) || (hSoup != nil))
  283.     {
  284.         // count how many style runs there are in the selection range
  285.         firstRun = _WEOffsetToRun(rangeStart, hWE);
  286.         nRuns = _WEOffsetToRun(rangeEnd - 1, hWE) - firstRun + 1;
  287.  
  288.         if (hStyles != nil)
  289.         {
  290.             // resize the given style scrap handle and lock it in high heap
  291.             SetHandleSize(hStyles, (nRuns * sizeof(ScrpSTElement)) + sizeof(SInt16));
  292.             if ((err = MemError()) != noErr)
  293.                 goto cleanup;
  294.             HLockHi(hStyles);
  295.  
  296.             // fill in the style count in the style scrap
  297.             // *** POTENTIAL PROBLEM: if nRuns > 32767, scrpNStyles will be invalid ***
  298.             WEASSERT(nRuns <= SHRT_MAX, "\pToo many styles");
  299.             (* (TEStyleScrapHandle) hStyles)->scrpNStyles = nRuns;
  300.         }
  301.  
  302.         pElement = & ((* (TEStyleScrapHandle) hStyles)->scrpStyleTab[0]);
  303.         // loop through every style run in the selection range
  304.         for ( i = 0; i < nRuns; i++ )
  305.         {
  306.             _WEGetIndStyle(firstRun + i, &info, hWE);
  307.  
  308.             // calculate the start character for this style run, relative to the beginning of the range
  309.             startChar = info.runStart - rangeStart;
  310.             if (startChar < 0)
  311.             {
  312.                 startChar = 0;
  313. #if WASTE_OBJECTS
  314.                 info.runAttrs.runStyle.tsObject = nil;
  315. #endif
  316.             }
  317.             if (hStyles != nil)
  318.             {
  319.                 info.runAttrs.runStyle.tsFlags = 0; // don't export internal flags
  320.                 pElement->scrpStartChar = startChar;
  321.                 pElement->scrpTEAttrs = * (TERunAttributes *) &info.runAttrs;
  322.                 pElement++;
  323.             }
  324.  
  325. #if WASTE_OBJECTS
  326.             if (hSoup != nil)
  327.             {
  328.                 // if this style run references an embedded object, append it to the "soup"
  329.                 if (info.runAttrs.runStyle.tsObject != nil)
  330.                 {
  331.                     if ((err = _WEAppendObject(hSoup, &info, startChar)) != noErr)
  332.                         goto cleanup;
  333.                 }
  334.             }
  335. #endif
  336.  
  337.         }
  338.     }
  339.     // clear result code
  340.     err = noErr;
  341.  
  342. cleanup:
  343.  
  344.     // unlock the style scrap handle
  345.     if (hStyles != nil)
  346.         HUnlock(hStyles);
  347.  
  348.     // unlock the WE record
  349.     _WESetHandleLock((Handle) hWE, saveWELock);
  350.     // return result code
  351.     return err;
  352. }
  353.  
  354. pascal OSErr WECopy(WEHandle hWE)
  355. {
  356.     // Copy the selection range to the desk scrap
  357.  
  358.     WEPtr pWE;
  359.     AEDesc d[3] = { { kTypeText, nil }, { kTypeStyles, nil }, { kTypeSoup, nil } };
  360.     Handle hItem;
  361.     Size itemSize;
  362.     SInt16 i, numTypes;
  363.     Boolean saveWELock;
  364.     Boolean saveDataLock;
  365.     Boolean disposeData = true;
  366.     OSErr err;
  367. #if WASTE_OBJECTS
  368.     WEObjectDescHandle hObjectDesc = nil;
  369. #endif
  370.  
  371.     // lock the WE record
  372.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  373.     pWE = *hWE;
  374.  
  375.     // return weEmptySelectionErr if the selection range is empty
  376.     if (pWE->selStart == pWE->selEnd)
  377.     {
  378.         err = weEmptySelectionErr;
  379.         goto cleanup;
  380.     }
  381.  
  382.     // clear the desk scrap
  383.     if ((err = ZeroScrap()) != noErr)
  384.         goto cleanup;
  385.  
  386. #if WASTE_OBJECTS
  387.     numTypes = (BTST(pWE->features, weFMonoStyled) || (WEGetSelectedObject(&hObjectDesc, hWE) == noErr)) ? 1 : 3;
  388. #else
  389.     numTypes = BTST(pWE->features, weFMonoStyled) ? 1 : 2;
  390. #endif
  391.  
  392.     // allocate some temporary handles
  393.     for ( i = 0; i < numTypes; i++ )
  394.     {
  395.         if ((err = _WEAllocate(0, kAllocTemp, &d[i].dataHandle)) != noErr)
  396.             goto cleanup;
  397.     }
  398.  
  399. #if WASTE_OBJECTS
  400.     if (hObjectDesc != nil)
  401.     {
  402.         if ((err = _WEStreamObject(weToScrap, &d[0].descriptorType, &d[0].dataHandle,
  403.                     &disposeData, hObjectDesc)) != noErr)
  404.             goto cleanup;
  405.     }
  406.     else
  407. #endif
  408.     {
  409.         // make a copy of the selection text and styles and create an object "soup"
  410.         if ((err = WECopyRange(pWE->selStart, pWE->selEnd,
  411.             d[0].dataHandle, d[1].dataHandle, d[2].dataHandle, hWE)) != noErr)
  412.             goto cleanup;
  413.     }
  414.  
  415.     // copy the items to the desk scrap
  416.     for ( i = 0; i < numTypes; i++ )
  417.     {
  418.         hItem = d[i].dataHandle;
  419.         itemSize = GetHandleSize(hItem);
  420.         if (itemSize > 0)
  421.         {
  422.             saveDataLock = _WESetHandleLock(hItem, true);
  423.             err = PutScrap(itemSize, d[i].descriptorType, *hItem);
  424.             _WESetHandleLock(hItem, saveDataLock);
  425.             if (err != noErr)
  426.                 goto cleanup;
  427.         }
  428.     }
  429.  
  430.     // clear result code
  431.     err = noErr;
  432.  
  433. cleanup:
  434.     // clean up
  435.     if (disposeData)
  436.     {
  437.         _WEForgetHandle(&d[0].dataHandle);
  438.         _WEForgetHandle(&d[1].dataHandle);
  439.         _WEForgetHandle(&d[2].dataHandle);
  440.     }
  441.     _WESetHandleLock((Handle) hWE, saveWELock);
  442.     return err;
  443. }
  444.